<!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>**基础**</title>
        <style>
</style>
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.10.2/dist/katex.min.css" integrity="sha384-yFRtMMDnQtDRO8rLpMIKrtPCD5jdktao2TV19YiZYWMDkUR5GQZR/NOVTdquEx1j" crossorigin="anonymous">
<link href="https://cdn.jsdelivr.net/npm/katex-copytex@latest/dist/katex-copytex.min.css" rel="stylesheet" type="text/css">
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/Microsoft/vscode/extensions/markdown-language-features/media/markdown.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/Microsoft/vscode/extensions/markdown-language-features/media/highlight.css">
<style>
            body {
                font-family: -apple-system, BlinkMacSystemFont, 'Segoe WPC', 'Segoe UI', system-ui, 'Ubuntu', 'Droid Sans', sans-serif;
                font-size: 14px;
                line-height: 1.6;
            }
        </style>
        <style>
.task-list-item { list-style-type: none; } .task-list-item-checkbox { margin-left: -20px; vertical-align: middle; }
</style>
        
        <script src="https://cdn.jsdelivr.net/npm/katex-copytex@latest/dist/katex-copytex.min.js"></script>
        
    </head>
    <body class="vscode-light">
        <h1 id="基础"><strong>基础</strong></h1>
<h2 id="java语言的优点"><strong>Java语言的优点：</strong></h2>
<ol>
<li>Java是纯面向对象的语言。</li>
<li>平台无关性。编译后的字节码运行在JVM上。</li>
<li>Java提供了很多类库。</li>
<li>提供了对Web应用开发的支持。</li>
<li>具有安全性、健壮性。</li>
<li>去除了C++中难以理解、容易混淆的特性。</li>
</ol>
<h2 id="java与c的区别"><strong>Java与C++的区别：</strong></h2>
<p>相同点：都是面向对象的语言。<br>
不同点：</p>
<ol>
<li>Java是解释型语言， C++是编译型语言。
解释型语言：编译后，由软件解释执行。
编译型语言：编译、链接后生成可执行的二进制代码。因此，解释型语言比编译型语言慢。</li>
<li>Java是纯面向对象的语言，不能定义全局变量和全局函数。C++兼具面向对象和面向过程的编程特点，可以定义全局变量和全局函数。</li>
<li>Java没有指针的 概念，操作指针可能引发系统问题，从而使程序变得更安全。</li>
<li>Java不支持多重继承，但是Java引入了接口（interface）的概念，可以同时实现（implement）多个接口。由于接口也具有多态的特性，因此Java语言中可以通过实现多个接口达到C++的多重继承类似的目的。</li>
<li>C/C++需要开发人员管理对内存的分配，Java语言提供了垃圾回收器(GC)来自动回收。当GC将要释放无用对象时，会首先调用该对象的finalize()的方法。</li>
</ol>
<h2 id="jvm-调优"><strong>JVM 调优</strong></h2>
<ol>
<li>-xmx3500m jvm最大可用内存</li>
<li>-xmn2g <strong>年轻代内存大小</strong> JVM内存大小=<strong>年轻代大小</strong> + 年老代大小 + 持久代大小</li>
<li>-xms3500m 初始内存</li>
<li>-Xss128k：设置每个线程的堆栈大小。JDK5.0以后每个线程堆栈大小为1M，以前每个线程堆栈大小为256K。</li>
</ol>
<h2 id="说一下-jvm-的主要组成部分及其作用">说一下 jvm 的主要组成部分？及其作用？</h2>
<p>类加载器（ClassLoader）
运行时数据区（Runtime Data Area）
执行引擎（Execution Engine）
本地库接口（Native Interface）</p>
<h2 id="什么是反射机制"><strong>什么是反射机制</strong></h2>
<p>反射是java的一个非常重要的特性，它允许程序在运行时<strong>自我检查</strong>，允许对其<strong>内部成员进行操作</strong></p>
<h2 id="package的作用"><strong>package的作用</strong></h2>
<p>package关键字 package名;<br>
javac -d . java源文件 会在当前目录下生成包文件夹（-d .）</p>
<ol>
<li>提供多层命名空间，解决命名冲突</li>
<li>对类按功能分类，使项目的组织更加清晰</li>
</ol>
<h2 id="如何实现c语言中函数指针的功能"><strong>如何实现C语言中函数指针的功能</strong></h2>
<p>利用<strong>接口和类</strong>实现相同的功能。</p>
<h2 id="finalfinally和finalize分别是什么"><strong>final、finally和finalize()分别是什么</strong></h2>
<p>final:修饰方法：方法不能重写；修饰变量：变量值不能修改、修饰类：类不能被继承。<br>
finally:异常处理最后执行的。<br>
finalize():每个对象释放是首先调用的函数。</p>
<h3 id="finally什么时候执行下面程序的运行结果是什么是">finally什么时候执行？下面程序的运行结果是什么是？</h3>
<pre><code><code><div>public class Demo{
    public static void main(String[] args){
        System.out.println(test());
    }
    
    public static int test(){
        try{
            System.out.println(1);
            return amethod(2);
        }catch(Exception e){
            System.out.println(3);
        } finally{
            return amethod(4);
        }
    }

    public static int amethod(int k){
        System.out.println(k);
        return k;
    }
}
</div></code></code></pre>
<details>
<summary>答案</summary>
<p>1<br>
2<br>
4<br>
4<br>
解析： 调用test（）方法，执行Syso(1), 然后调用amethod(2)；finally总是执行，执行amethod(4)； 由于finally中有return，finally中的return覆盖其他地方的return--返回4</p>
</details>
<hr>
<h1 id="面向对象的技术"><strong>面向对象的技术</strong></h1>
<h2 id="面向对象的特性"><strong>面向对象的特性：</strong></h2>
<p><strong>抽象 继承 封装 多态</strong></p>
<ol>
<li>抽象：忽略一个主题中与当前目标无关的那些方面，分为过程抽象，数据抽象</li>
<li>继承：继承是一种<strong>联结类的层次模型</strong>，<strong>新类可以从现有的类中派生</strong>。子类可以从基类继承<u>方法和实例变量</u>，派生类可以<u>增加或修改新的方法</u>使之适合特殊的需求。</li>
<li>封装：将客观事物封装成类，每个类对自身的数据和方法<strong>实行保护</strong>。</li>
<li>多态：多态就是<u>同一个接口或类</u>，使用不同的实例而<u>执行不同操作</u></li>
</ol>
<h2 id="面向对象的优点"><strong>面向对象的优点</strong></h2>
<ol>
<li>较高的开发效率。抽象将现实中的事物映射为开发的对象，与人类思维过程相似。面向对象的开发方式可以通过继承和组合来实现代码的重用。</li>
<li>保证软件的鲁棒性。</li>
<li>高可维护性。面向对象的开发方式可读性非常好，同时面向对象的设计模式也使得代码结构更加清晰明了。</li>
</ol>
<h2 id="什么是继承"><strong>什么是继承</strong></h2>
<ol>
<li>面向对象的重要特性</li>
<li>一种联结类的层次模型</li>
<li>继承是通过extends关键字实现的（class 派生类 extends 基类）</li>
</ol>
<blockquote>
<p>通过继承，子类可以直接使用父类的成员变量和方法，从而提高代码的复用率，提高开发效率。</p>
</blockquote>
<h2 id="组合"><strong>组合</strong></h2>
<details>
    <summary>什么是组合?</summary>
<p>新类里面创建原有类的对象，重复利用已有类的功能。代码表示如下：</p>
<pre><code>class A{
    B b = new B();
}
</code></pre>
</details>
<details>
    <summary>继承的代码表示?</summary>
<pre><code>class A{}  
class B extends A{}
</code></pre>
</details>
<h2 id="多态的机制是什么"><strong>多态的机制是什么?</strong></h2>
<details>
    <summary>Java中提供了哪两种用于多态的机制？</summary>
<blockquote>
<p>编译时多态和运行时多态</p>
</blockquote>
</details>
<details>
    <summary>编译时多态和运行时多态的表现方式是什么?</summary>
<ol>
<li>方法的重载（overload）。// 函数名相同，参数不同！</li>
<li>方法的覆盖（override）。// 重写</li>
</ol>
</details>
<p><strong>下面程序的运行结果是什么？</strong></p>
<pre><code>class A{
    public A(){
        g();
    }
    public void f(){
        System.out.println(&quot;A f()&quot;);
    }
    public void g(){
        System.out.println(&quot;A g()&quot;);
    }
}

class B extends A{
    public void f(){
        System.out.println(&quot;B f()&quot;);
    }
    public void g(){
        System.out.println(&quot;B g()&quot;);
    }
}

class Test{
    public static void main(){
        A a = new B();
        a.f();
        a.g();
    }
}
</code></pre>
<details>
<summary>答案</summary>  
<p>B g()<br>
B f()<br>
B g()<br>
<strong>解释：</strong><br>
在执行A a = new B();调用父类的构造函数A()，A中执行g()，由于java多态的特性调用的是子类的g()方法，因此输入B g()。由于创建的是B()对象，所以后面会调用子类B的方法。</p>
</details>
<hr>
<p>注意：类中的<strong>方法才有多态</strong>的概念，<strong>成员变量没有</strong>，成员变量的值，取决于定义<strong>变量的类型（A a）</strong><br>
子类或实现中有某个方法，父类或接口没有，调用会报错</p>
<hr>
<h2 id="重载和覆盖有什么区别"><strong>重载和覆盖有什么区别？</strong></h2>
<p><strong>重载：</strong>
在类中定义多个同名的方法，他们有不同的参数个数和不同的参数类型。<br>
<em>注意事项：</em></p>
<ol>
<li>根据参数区分</li>
<li>不能通过权限，返回值，抛出的异常类型重载</li>
<li>基类方法为private，那么派生类不能重载该方法</li>
</ol>
<p><strong>覆盖：</strong>
重写父类函数，以达到不同作用<br>
<em>注意事项:</em></p>
<ol>
<li>派生类和基类的函数名和参数必须一致。</li>
<li>覆盖方法的返回值必须和基类的返回值相同。</li>
<li>抛出的异常类型一致</li>
<li>基类覆盖的方法不能为private。</li>
</ol>
<p><strong>区别</strong></p>
<h2 id="内部类有哪些"><strong>内部类有哪些？</strong></h2>
<h2 id="关于object类"><strong>关于Object类：</strong></h2>
<h1 id="字节码对象">字节码对象</h1>
<h2 id="getresource方法">getResource()方法</h2>
<blockquote>
<p>getClass().getResource(&quot;/开头&quot;)</p>
</blockquote>
<p>不含包文件夹的路径，到<strong>包的根路径下</strong></p>
<blockquote>
<p>getClass().getResource(&quot;不以/开头&quot;)</p>
</blockquote>
<p>得到当前class文件的路径下的资源，<strong>含包文件夹</strong></p>
<blockquote>
<p>getClass().getClassLoader().getResource(&quot;/开头&quot;)</p>
</blockquote>
<p>返回null</p>
<blockquote>
<p>getClass().getClassLoader().getResource(&quot;不以/开头&quot;)</p>
</blockquote>
<p>不含包文件夹的路径，到<strong>包的根路径下</strong></p>
<h1 id="进程process">进程(Process)</h1>
<ol>
<li>进程的定义：
一个具有一定独立功能的程序在数据集合上的一次动态执行过程。这个过程就是进程。
例如：高级编译连接完一个程序后，生成文件系统中的可执行文件，该文件不能直接运行，当操作系统把它调入内存中，通过cpu执行指令。</li>
</ol>
<blockquote>
<p>qq的打开用户、群或设置界面其实就是进程</p>
</blockquote>
<ol start="2">
<li>进程的组成
<ul>
<li>一个进程包括：
<ul>
<li>程序代码(编译、连接好的)</li>
<li>程序处理的数据</li>
<li>程序计数器中的值，知识下一条将运行的指令</li>
<li>一组通用寄存器的当前值，堆、栈</li>
<li>一组系统资源(如打开的文件)</li>
</ul>
</li>
</ul>
</li>
</ol>
<blockquote>
<p>总之，进程包含了正在运行的一个程序的所有状态。</p>
</blockquote>
<ol start="3">
<li>进程与程序之间的练习：</li>
</ol>
<ul>
<li>程序是产生进程的基础</li>
<li>程序的每次运行构成不同的进程</li>
<li>进程是程序的体现</li>
<li>通过多次执行，一个程序可对应多个进程；通过调用关系，一个进程可包括多个程序</li>
</ul>
<ol start="4">
<li>进程与程序的的区别</li>
</ol>
<ul>
<li>进程是动态的，程序是静态的：程序是有序代码的集合；进程是程序的执行，进程有核心态(比如进程要操作文件，进程给操作系统发送请求，操作系统代表进程在内核中执行&lt;--简单理解为操作了内核--&gt;)/用户态</li>
<li>进程是暂时的，程序是永久的：进程是一个状态变化的过程，程序可长久保存</li>
<li>进程与程序的组成不同：进程组成包括程序、数据和进程控制块（即进程状态信息）</li>
</ul>
<ol start="6">
<li>进程的特点：</li>
</ol>
<ul>
<li>动态性：可动态地创建、结束进程</li>
<li>并发性：进程可以被独立调度并占用处理机运行；注：并发（极短的时间执行不同的）并行（同一时刻执行不同的）</li>
<li>独立性：不同进程的工作不互相影响</li>
<li>制约性：因为访问共享数据/资源进程间同步而产生的制约</li>
</ul>
<ol start="7">
<li>进程控制块</li>
</ol>
<p>程序 = 算法 + 数据结构
操作系统也是程序，进程控制块（PCB）则是操作系统的数据结构
操作系统为每个进程都维护了一个PCB,用于保存与该进程有关的各种状态信息。
8.	进程控制块结构<br>
进程控制块：操作系统管理控制进程程序运行所用的信息集合<br>
进程控制块：进程 = 1：1<br>
操作系统用PCB来描述进程的基本情况以及运行变换的过程，PCB是进程存在的唯一标志</p>
<h2 id="使用进程控制块">使用进程控制块：</h2>
<ul>
<li>进程的创建：为该进程生成一个PCB；</li>
<li>进程的终止：回收它的PCB；</li>
<li>进程的组织管理：对PCB的组织管理；</li>
</ul>
<h2 id="进程控制块包含了什么信息如何组织的进程的转换">进程控制块包含了什么信息？如何组织的？进程的转换：……</h2>
<p>PCB含有三大类信息</p>
<ul>
<li>进程标识信息。如本进程的标识，本进程的产生者标识（父进程标识）；用户标识。</li>
<li>处理机状态信息保存区。保存运行现场信息：
<ul>
<li>用户可见信息，用户程序可以使用的数据，地址等寄存器。</li>
<li>控制和状态寄存器，如程序寄存器（PC），程序状态字（PSW）。</li>
<li>栈指针，过程调用/系统调用/中断处理和返回时需要用到它</li>
</ul>
</li>
<li>进程的控制信息：（未完）
<ul>
<li>调度和状态信息，用于操作系统调度进程并占用处理机使用</li>
<li>进程间通信信息</li>
<li>存储管理信息</li>
<li>进程所有资源</li>
<li>有关数据结构连接信息</li>
</ul>
</li>
</ul>
<h1 id="线程">线程</h1>
<h2 id="线程的4种状态">线程的4种状态：</h2>
<ol>
<li>新建</li>
<li>就绪</li>
<li>运行</li>
<li>挂起</li>
<li>结束</li>
</ol>
<h2 id="概述">概述：</h2>
<p>线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中，是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流，一个进程中可以并发多个线程，每条线程并行执行不同的任务。</p>
<h2 id="线程实现方法">线程实现方法</h2>
<ol>
<li>继承Thread类创建线程,重写run()方法
创建Thread实例，调用start()</li>
<li>实现Runnable接口创建线程
实现run()方法，装载到Thread实例中，调用start()方法</li>
<li><strong>使用Callable和Future创建线程。</strong>(重点！！！！)</li>
</ol>
<ul>
<li>Callable接口提供了call()作为线程执行体</li>
<li>call可以有返回值,java5提供Future来代表Callable接口里call()方法的返回值，并为Future几口提供了实现类FutureTask，该实现类（FutureTask）既实现了Future接口，还实现了Runnable接口，因此作为Thread类的target。</li>
<li>call可以抛出异常</li>
<li>代码:<pre><code class="language-java"><div>    FutureTask&lt;返回类型&gt; futureTask = <span class="hljs-keyword">new</span> FutureTask&lt;&gt;(<span class="hljs-comment">//此处放Callable</span>
        ()-&gt;{
            <span class="hljs-keyword">return</span> 返回值；
        }
    );
    <span class="hljs-keyword">new</span> Thread(futureTask).start();
    futureTask.get();<span class="hljs-comment">//有阻塞功能,得到返回值</span>
</div></code></pre>
</li>
</ul>
<blockquote>
<p>多进程和多线程：多进程消耗资源高于多线程，java不支持多进程</p>
</blockquote>
<h2 id="java实现多线程的三种方法">java实现多线程的三种方法</h2>
<ol>
<li>
<p>继承Thread类创建线程类</p>
<ul>
<li>定义Thread类的子类，重写run（）方法。run()中方法体代表线程需要完成的任务，因此run（）称为方法执行体。</li>
<li>创建Thread子类的实例，即是创建线程对象。</li>
<li>调用start（）方法启动该线程</li>
</ul>
</li>
<li>
<p>实现Runnable接口创建线程类
（注：使用同一个对象，共享数据变得方便不需要将成员变量变成静态<static>）</p>
<ul>
<li>定义Runnable接口的实现类重写run（）方法执行体</li>
<li>实例化Runnable接口实现类，用该实例作为Thread的target来创建Thread对象，创建出来的对象即是新线程对象</li>
<li>程序创建的Runnable接口实现类的实例只是线程的target，如果程序共享了一个target，那么多个线程公用一个线程类</li>
</ul>
</li>
<li>
<p>使用Callable接口和Future创建线程（用于有返回值的函数&lt;行为&gt;）
属于juc编程（import java.util.concurrent）,熟悉juc编程</p>
<ul>
<li>
<p>使用Callable接口实现类作为Thread的target
Callable：
call（）；//执行函数
注意1：call()可以有返回值
注意2：call()方法可以声明抛出异常</p>
</li>
<li>
<p>Future接口代表Callable接口里call()方法的返回值，并为Future接口提供了一个FutureTask实现类该实现类实现了Future接口，并实现了Runnable接口（Runnable的实现类可以作为Thread类的target）</p>
</li>
<li>
<p>Future提供了如下公共方法实现Callable任务：
boolean cancel(boolean mayInterrupIfRunning):试图取消该Future里关联的Callable任务。
V get（）：返回Callable任务里call()方法的返回值。调用该方法会导致程序堵塞，必须等到子线程结束后才会有返回值。
V get（long timeout,TimeUnit unit）:返回Callable任务里call()方法的返回值。该方法最多堵塞timeout和time指定的时间，如果经过指定时间后Callable任务依然没有返回值，将会抛出TimeoutException异常。
boolean isCancelled（）：如果在Callable任务正常完成前取消，则返回true。
boolean isDone（）：如果Callable任务已经完成，则返回true</p>
</li>
</ul>
</li>
</ol>
<h2 id="run-方法和-start有什么区别">run 方法和 start有什么区别</h2>
<ol>
<li>start来启动一个线程。异步调用run方法。</li>
<li>JVM调用run方法来完成实际操作。直接调用run方法，该方法只能作为普通方法执行</li>
</ol>
<h2 id="sleep-方法和wait方法有什么区别">sleep() 方法和wait()方法有什么区别</h2>
<ol>
<li>sleep是使线程暂停一段时间。</li>
<li>wait调用后对象进入等待状态，直到被唤醒或等待超时。</li>
<li>sleep是Tread的静态方法，是线程用来控制自身流程的。</li>
<li>wait是Object的方法用于线程间的通信。直到其他线程调用notify（notifyAll）方法。开发人员可以给定时间让他超时。</li>
<li>对锁的处理机制不同，sleep不会释放锁，当调用wait会释放它所占用的锁。</li>
<li>sleep可以放到任何地方，wait必须放到同步控制方法或者同步语句块中使用。</li>
<li>sleep抛出异常，wait不抛出。</li>
</ol>
<h2 id="sleep和yield方法有什么区别">sleep和yield方法有什么区别</h2>
<ol>
<li>yield给相同优先级或更高优先级运行的机会</li>
<li>yield使用后当前线程有可能直接被调用</li>
<li>sleep声明InterruptedException， yield没有生命任何异常</li>
<li>sleep方法比yield方法有更好的可移植性。</li>
</ol>
<h2 id="原子操作java解决同步问题的关键字">原子操作（java解决同步问题的关键字）</h2>
<ol>
<li>使用synchronized(锁){}</li>
<li>使用同步函数（常用的考点）</li>
<li>使用synchronized修饰</li>
</ol>
<blockquote>
<p>非静态synchronized方法锁是this；静态synchronized方法锁是当前类的字节码对象<br>
注意：同一个原子操作应该用同一把锁</p>
</blockquote>
<h2 id="线程同步问题">线程同步问题</h2>
<ol>
<li>使用原子操作</li>
<li>使用wait()和notify()方法</li>
<li>Lock JDK5,及其实现类ReentrantLock
<ul>
<li>lock() 方法，以阻塞的方式获取锁。</li>
<li>tryLock() 以非阻塞的方式获取锁。</li>
<li>tryLock(long timeout, TimeUnit unit) 获取锁，获取不到等待，直到超时。</li>
<li>lockInterruptibly(), 获取锁， 当前线程处于休眠状态，直到获取锁，或者当前线程被别的线程中断。</li>
</ul>
</li>
</ol>
<h2 id="终止线程的方法">终止线程的方法</h2>
<ol>
<li>使用stop()，会释放已经锁定的所有监视资源。</li>
<li>使用suspend()容易发生死锁</li>
</ol>
<h2 id="thread的sleepyieldwaitsetpriority方法">Thread的sleep、yield、wait、setPriority方法</h2>
<ol>
<li>sleep指定线程休眠一部分时间（把小鸡打晕一段时间），抛出了InterruptedException异常</li>
<li>yiled指定线程让出cpu的占用权（就是把小鸡打晕，可能用力不够马上就继续吃食），不抛异常</li>
<li>wait让线程进入等待状态</li>
<li>setPriority指定线程的优先级</li>
</ol>
<blockquote>
<p>作业：写一个线程安全的买票程序，每个窗口代表一个线程输入窗口数和票数，输出谁卖了哪张票</p>
</blockquote>
<h2 id="join和juc编程的countdownlatch">join和JUC编程的CountDownLatch</h2>
<ol>
<li>join()表示当前线程运行完后运行后面的</li>
<li>CountDownLatch创建对象构造函数中代表减多少个数后开始运行后面的程序</li>
</ol>
<blockquote>
<p>作业：使用CountDownLatch实现运动员跑步的总里程数，输入n个运动员在线程中随机生成100 – 1000的里程数&lt;使用CountDownLatch和join&gt;</p>
</blockquote>
<h2 id="并行和并发">并行和并发</h2>
<ol>
<li>并发：极短的时间开始，让人感觉是同时开始</li>
<li>并行：多个进程同时运行，多个线程同时进行</li>
</ol>
<h2 id="线程通信">线程通信</h2>
<ol>
<li>Object对象中的方法：（全是final声明的不能重写）</li>
<li>wait():告诉当前线程放弃对象监视器（锁），进入到等待状态，直到等到在这个对象监视器（锁）上的notify（通知）为止</li>
<li>notify():通知等待锁的哪个线程运行</li>
<li>notify():通知等待锁的所有线程运行</li>
</ol>
<h2 id="生产者消费者问题a和b都使用资源c只需要提前判断c是否被使用如果在使用wait使用完后通知">生产者消费者问题：A和B都使用资源C,只需要提前判断C是否被使用,如果在使用wait()，使用完后通知</h2>
<blockquote>
<p>作用：生产者消费者问题
线程安全的类：StringBuffer、Vector、Hashtable、ConcurrentHashMap，StringBuilder不是
线程安全都用synchronized同一把锁，线程安全会付出时间的代价</p>
</blockquote>
<h2 id="collections中关于同步的方法">Collections中关于同步的方法</h2>
<ol>
<li>synchronizedXXX（XXX）；将XXX的值变为线程安全的。</li>
<li>iterator()方法不是线程安全的</li>
<li>线程安全的方法集合在一起可能不安全</li>
</ol>
<h2 id="synchronized-与-lock有什么区别">synchronized 与 Lock有什么区别:</h2>
<ol>
<li>用法不一样
<ul>
<li>synchronized作用在方法和特定代码块上，托管给JVM。</li>
<li>Lock通过代码实现，显式地指定其实位置和终止位置。</li>
</ul>
</li>
<li>性能不一样
<ul>
<li>JDK5中增加了Lock接口的实现类ReentrantLock。它拥有和synchronized有相同的并发性和内存语义。（增添了锁投票，定时锁，等候和中断锁等）</li>
<li>在资源竞争不是特别激烈的情况下，synchronized的性能优于ReentrantLock</li>
<li>在资源竞争特别激烈的情况下，synchronized的性能会下降得非常快，ReentranLock性能基本保持不变。</li>
</ul>
</li>
<li>锁机制不一样
<ul>
<li>sychronized获得锁和释放锁是在代码块中，获得多个锁时，必须以相反顺序释放，并且是自动解锁。</li>
<li>Lock需要程序员手动释放，并且在finally中释放，否者会引发死锁问题的发生，Lock可以通过tryLock()采用非阻塞的方式区获取锁。</li>
</ul>
</li>
</ol>
<blockquote>
<p>注意：不要同时使用两种方式获取锁。</p>
</blockquote>
<h2 id="什么是守护线程">什么是守护线程</h2>
<ol>
<li>java中提供了两种线程：守护线程和用户线程。</li>
<li>守护线程又称“服务线程”，“精灵线程”，“后台线程”</li>
<li>用户线程全部退出，只剩下守护线程存在，JVM也就退出</li>
<li>守护线程并非只有jvm能提供。用户在调用start()方法前，调用setDaemon(true)，就能创建守护线程，若设为false则表示用户线程。</li>
<li>守护线程产生新的线程，新产生的线程默认还是守护线程，同理用户线程也是默认产生用户线程。</li>
<li>守护线程最典型的例子：垃圾回收器，jvm启动，它始终运行，实时监控和管理系统中可以被回收的资源。</li>
</ol>
<h2 id="join-的作用">join() 的作用</h2>
<p>两个线程合并，用于实现同步功能。可以设置等待时间。</p>
<h2 id="线程池juc">线程池（JUC）</h2>
<h3 id="内置的线程池executorservice接口通过executors获取newxxxx">内置的线程池：ExecutorService接口通过Executors获取newxxxx</h3>
<h3 id="常用方法">常用方法</h3>
<ol>
<li>execute提交后没返回值</li>
<li>submit提交有返回值</li>
<li>newFixedThreadPool(线程的个数):线程个数固定</li>
<li>newSingleThreadExecutor（单线程）</li>
<li>ThreadPoolExecutor（核心线程数量, 最大线程数, TimeUnit最大空闲时间,  时间单位, 任务队列， 线程工厂, 饱和处理机制）</li>
<li>ExecutorService:关闭线程池</li>
<li>shutdown（）//关闭，不再允许接受新的任务</li>
<li>shutdownNow()//立刻关闭线程池，如果线程池中还有任务，立刻取消，并返回这些任务</li>
</ol>
<h3 id="不参与线程创建的方法">不参与线程创建的方法：</h3>
<pre><code class="language-java"><div>ExecutorService es = Executors.newCachedThreadRool();
<span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">10</span> ; i++){
    es.submit(<span class="hljs-keyword">new</span> MyRunnable());
}
</div></code></pre>
<h3 id="参与线程创建的方法">参与线程创建的方法：</h3>
<pre><code class="language-java"><div>ExecutorService es = Executors.newCachedThreadRool(
    <span class="hljs-keyword">new</span> ThreadFactory(){
        <span class="hljs-function"><span class="hljs-keyword">public</span> Thread <span class="hljs-title">newThread</span><span class="hljs-params">(Runnable r)</span></span>{
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Thread(r);
        }
    }
);
<span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">10</span> ; i++){
    es.submit(<span class="hljs-keyword">new</span> MyRunnable());
}
</div></code></pre>
<h3 id="三种创建线程池的方法">三种创建线程池的方法</h3>
<pre><code class="language-java"><div>	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">test1</span><span class="hljs-params">()</span> </span>{
		ExecutorService es = Executors.newCachedThreadPool();
		<span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">10</span>; i++)
			es.submit(<span class="hljs-keyword">new</span> MyRunnable());
		
		ExecutorService es1 = Executors.newCachedThreadPool(<span class="hljs-keyword">new</span> ThreadFactory() {
			<span class="hljs-function"><span class="hljs-keyword">public</span> Thread <span class="hljs-title">newThread</span><span class="hljs-params">(Runnable r)</span> </span>{
				<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Thread(r);
			}
		});
		<span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">10</span>; i++)
			es1.execute(<span class="hljs-keyword">new</span> MyRunnable());
	}
	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">test2</span><span class="hljs-params">()</span> </span>{
		ExecutorService es = Executors.newFixedThreadPool(<span class="hljs-number">3</span>);
		<span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">10</span>; i++)
			es.submit(<span class="hljs-keyword">new</span> MyRunnable());
		ExecutorService es1 = Executors.newFixedThreadPool(<span class="hljs-number">3</span>, <span class="hljs-keyword">new</span> ThreadFactory() {
			<span class="hljs-function"><span class="hljs-keyword">public</span> Thread <span class="hljs-title">newThread</span><span class="hljs-params">(Runnable r)</span> </span>{
				<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Thread(r);
			}
		});
		<span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">10</span>; i++)
			es1.submit(<span class="hljs-keyword">new</span> MyRunnable());
	}
	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">test3</span><span class="hljs-params">()</span> </span>{
		ExecutorService es = Executors.newSingleThreadExecutor();
		<span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">10</span>; i++)
			es.submit(<span class="hljs-keyword">new</span> MyRunnable());
		ExecutorService es1 = Executors.newSingleThreadExecutor(<span class="hljs-keyword">new</span> ThreadFactory() {
			<span class="hljs-function"><span class="hljs-keyword">public</span> Thread <span class="hljs-title">newThread</span><span class="hljs-params">(Runnable r)</span> </span>{
				<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Thread(r);
			}
		});
		<span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">10</span>; i++)
			es1.submit(<span class="hljs-keyword">new</span> MyRunnable());
	}
    <span class="hljs-comment">// 另一个类</span>
    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyRunnable</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Runnable</span></span>{
        <span class="hljs-meta">@Override</span>
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">run</span><span class="hljs-params">()</span> </span>{
            String name = Thread.currentThread().getName();
            System.out.println(name + <span class="hljs-string">"执行了"</span>);
        }
    }
</div></code></pre>
<h2 id="定时器">定时器：</h2>
<h3 id="timer线程-定时执行某一函数功能">Timer线程： 定时执行某一函数（功能）</h3>
<h3 id="使用方法">使用方法</h3>
<ol>
<li>定义TimerTask, 计划任务的内容（需要自己跑的内容）</li>
<li>定义一个Timer： 起定时作用</li>
<li>设置任务多长时间执行一次, timer.schedule(timerTask, 第一次执行的时间--ms， 经历第一次后多长时间运行一次--ms)</li>
<li>关闭TimerTask的引用.cancel()</li>
</ol>
<h1 id="集合框架">集合框架</h1>
<h2 id="java-collection-框架是什么">Java Collection 框架是什么</h2>
<ol>
<li>Collection包含了大量的接口的实现类和操作它们的算法。</li>
<li>主要提供了List（列表）、Queue（队列）、Set（集合）、Stack（栈）、Map（映射表）等数据结构。</li>
<li>其中List、Set、Queue、Stack都继承自Collection接口。</li>
</ol>
<h3 id="set接口">Set接口</h3>
<ol>
<li>不重复，确保equals()唯一性！</li>
<li>Set接口有两个实现类：TreeSet（又实现了SortSet， 所以有序）， HashSet</li>
</ol>
<h4 id="hashset添加">HashSet添加</h4>
<pre><code class="language-java"><div><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">testHashSetAddMethod</span><span class="hljs-params">()</span> </span>{
    HashSet set = <span class="hljs-keyword">new</span> HashSet();
   
	<span class="hljs-comment">// 一定要重写 Person 的 hashCode() 和 equals() ！！！</span>
    Person p1 = <span class="hljs-keyword">new</span> Person(<span class="hljs-number">1001</span>, <span class="hljs-string">"AA"</span>);
    Person p2 = <span class="hljs-keyword">new</span> Person(<span class="hljs-number">1002</span>, <span class="hljs-string">"BB"</span>);

    set.add(p1);
    set.add(p2);
    p1.setName(<span class="hljs-string">"CC"</span>);

    <span class="hljs-comment">/*
    先计算 p1(1001, "CC") 的哈希值，然后根据某种算法(&amp;)，计算出 p1(1001, "CC")
    在数组中的索引位置，在很大概率上 p1(1001, "CC") 不会落在 原p1(1001, "AA")、p2(1002, "BB")
    的位置上，所以 remove 了一个寂寞
     */</span>
    set.remove(p1);
    System.out.println(set); <span class="hljs-comment">// 1001 "CC"、1002 "BB"</span>

    <span class="hljs-comment">/*
    先计算匿名对象 (1001, "CC") 的哈希值，然后根据某种算法(&amp;)，计算出此匿名对象
    在数组中的索引位置，在很大概率上此匿名对象不会落在
     p1(这里的 p1 的哈希值还是 (1001, "AA")的哈希值)、p2的位置上，所以会添加成功
     */</span>
    set.add(<span class="hljs-keyword">new</span> Person(<span class="hljs-number">1001</span>, <span class="hljs-string">"CC"</span>));
    System.out.println(set); <span class="hljs-comment">// 1001 "CC"、1001 "CC"、1002 "BB"</span>

    <span class="hljs-comment">/*
    先计算此匿名对象 (1001, "AA") 的哈希值，然后根据某种算法(&amp;)，计算出此匿名对象
    在数组中的索引位置，这个索引位置就是 p1(1001, "CC") 的位置(相同的对象拥有相同的哈希值)，
    然后调用此匿名对象所在类的 equals() 与 p1(1001, "CC") 作比较，返回 false，
    所以此匿名对象能够添加成功
     */</span>
    set.add(<span class="hljs-keyword">new</span> Person(<span class="hljs-number">1001</span>, <span class="hljs-string">"AA"</span>));
    System.out.println(set); <span class="hljs-comment">// 1001 "AA"、1001 "CC"、1001 "CC"、1002 "BB"</span>
}

<span class="hljs-comment">// Person 方法如下：</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Person</span> </span>{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> id;
    <span class="hljs-keyword">private</span> String name;
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Person</span><span class="hljs-params">(<span class="hljs-keyword">int</span> id, String name)</span> </span>{
        <span class="hljs-keyword">this</span>.id = id;
        <span class="hljs-keyword">this</span>.name = name;
    }
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getId</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> id;
    }
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setId</span><span class="hljs-params">(<span class="hljs-keyword">int</span> id)</span> </span>{
        <span class="hljs-keyword">this</span>.id = id;
    }
    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">getName</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> name;
    }
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setName</span><span class="hljs-params">(String name)</span> </span>{
        <span class="hljs-keyword">this</span>.name = name;
    }
    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">equals</span><span class="hljs-params">(Object o)</span> </span>{
        <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span> == o) <span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>;
        <span class="hljs-keyword">if</span> (o == <span class="hljs-keyword">null</span> || getClass() != o.getClass()) <span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>;
        Person person = (Person) o;
        <span class="hljs-keyword">return</span> id == person.id &amp;&amp;
                Objects.equals(name, person.name);
    }
    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">hashCode</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> Objects.hash(id, name);
    }
    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">toString</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">"Person{"</span> +
                <span class="hljs-string">"id="</span> + id +
                <span class="hljs-string">", name='"</span> + name + <span class="hljs-string">'\''</span> +
                <span class="hljs-string">'}'</span>;
    }
}

<span class="hljs-comment">/*
运行结果：
[Person{id=1002, name='BB'}, Person{id=1001, name='CC'}]
[Person{id=1002, name='BB'}, Person{id=1001, name='CC'}, Person{id=1001, name='CC'}]
[Person{id=1002, name='BB'}, Person{id=1001, name='CC'}, Person{id=1001, name='CC'}, Person{id=1001, name='AA'}]
*/</span>
</div></code></pre>
<h3 id="list接口">List接口</h3>
<ol>
<li>按对象进入的顺序保存对象</li>
<li>可以保存重复的对象</li>
<li>LinkedList，ArrayList和Vector都实现了List接口。</li>
</ol>
<h3 id="map接口">Map接口</h3>
<ol>
<li>Map接口的实现类：HashMap，TreeMap，LinkedHashMap，WeakHashMap，IdentityHashMap。</li>
<li>HashMap基于散列表实现的，采用对象的<strong>HashCode</strong>进行快速查询。</li>
<li>LinkedHashMap采用<strong>列表</strong>来维护累不的顺序。</li>
<li>TreeMap基于红黑树的数据结构来实现的，内部元素是按需排列的。</li>
</ol>
<h3 id="arraylistvector和linkedlist有什么区别">ArrayList、Vector和LinkedList有什么区别：</h3>
<ol>
<li>ArrayList和Vector都是基于Object[]实现的，他们都有一个初始化容量大小，当容量超过这个大小时，会动态的扩充他们的容量。</li>
<li>Vector默认扩容为原来的2倍，扩容空间大小可以设置。List默认扩容为原来的1.5倍，没有提供设置扩容大小的方法。</li>
<li>Vector是线程安全的，ArrayList没有一个方法是同步的，非线程安全的。所以Vector性能略逊于ArrayList。</li>
<li>LinkedList:双向链表，增加、删除快，非线程安全。</li>
</ol>
<h3 id="hashmap-treemap-hashtable-weakhashmap有哪些区别">HashMap, TreeMap, HashTable, WeakHashMap有哪些区别：</h3>
<ol>
<li>java.util.Map的实现类： HashMap、TreeMap、HashTable</li>
<li>HashMap是HashTable的轻量级实现，HashMap允许键值为null，HashTable不允许。</li>
<li>HashMap去掉了HashTable的contains方法，改为containsValue和containsKey。HashTable继承自Dictionary，HashMap是Java1.2 引进Map的实现。</li>
<li>HashTable是线程安全的。HashMap非线程安全。</li>
<li>Hashtable使用Enumeration遍历，HashMap使用Iterator</li>
<li>Hashtable和HashMap采用的hash/rehash算法几乎一样。</li>
<li>Hashtable数组默认大小为11， 增长方式：old * 2 + 1。 HashMap默认大小是16，空间一定是2的指数倍。</li>
<li>TreeMap实现了SortMap接口。有序。</li>
<li>WeakHashMap中的key采用弱引用，只要key不被外部引用，就被回收。</li>
<li>ConcurrentHashMap不仅线程安全而且效率高，使用分段技术，给每一段数据加了一把锁。</li>
<li>HashMap内部的Node数组默认的大小是16，为了解决这个问题，HashMap提供了自动扩容机制，当元素个数达到数组大小loadFactor后会扩大数组的大小，在默认情况下，数组大小为16，loadFactor为0.75，也就是说当HashMap中的元素超过16/0.75=12时，会把数组大小扩展为2*16=32，并且重新计算每个元素在新数组中的位置。</li>
</ol>
<h3 id="如何实现hashmap的同步">如何实现HashMap的同步：</h3>
<details>
<summary>答案</summary>
通过Map m = Collections.synchronizedMap(new HashMap())。
</details>
<h1 id="关于泛型"><strong>关于泛型：</strong></h1>
<h3 id="">&lt;?&gt;</h3>
<p>接受，使用Object 遍历</p>
<h3 id="-extends-t">&lt;? extends T&gt;</h3>
<p>赋值：接受T和T的子类数据，无法put</p>
<h3 id="-super-t">&lt;? super T&gt;</h3>
<p>赋值：接受T和T的父类数据， 无法get</p>
<h1 id="nionew-io-nonblocking-io-非阻塞流jdk14开始">NIO(New I/O, Nonblocking IO)， 非阻塞流，JDK1.4开始</h1>
<h2 id="传统io流">传统I/O流：</h2>
<ol>
<li>线程会被阻塞，CPU利用率低，系统吞吐量低。例如网络通讯，接受数据。</li>
<li>面向流</li>
</ol>
<h2 id="nio">NIO</h2>
<ol>
<li>面向块（面向缓冲区）</li>
<li>非阻塞</li>
<li>核心API：Channel（通道）， Buffer（缓冲）， Selector</li>
</ol>
<h2 id="channel通道">Channel（通道）</h2>
<ol>
<li>通道可以<strong>同时读写</strong>， 传统流不能</li>
<li>通道可以实现异步读写数据</li>
<li>通道可以从缓冲中读数据，也可以写数据到缓冲中</li>
</ol>
<h2 id="buffer缓冲">Buffer（缓冲）</h2>
<p>使用步骤</p>
<ol>
<li>写数据到缓冲区</li>
<li>调用buffer的flip()方法</li>
<li>从缓冲区读取数据</li>
<li>调用buffer的clear()或compat()方法</li>
</ol>
<p>buffer写入数据，buffer会记录写入的数据，一旦要读取数据通过flip()方法将buffer从写模式切换到读模式，在读模式下读取之前写入的buffer的所有数据，一旦读完了多有的数据，就需要清空缓冲区，让它可以再次被写入。</p>
<h2 id="buffer的三个关键属性">Buffer的三个关键属性：</h2>
<p>容量大小 -- capacity
当前读/写的位置 -- position
信息末尾的位置 -- limit</p>
<h2 id="向buffer写入数据">向Buffer写入数据：</h2>
<ol>
<li>从Channel写到Buffer</li>
<li>通过Buffer的put方法写道Buffer中</li>
</ol>
<h2 id="从buffer读取数据">从Buffer读取数据：</h2>
<ol>
<li>从Buffer中读取数据到Channel</li>
<li>通过Buffer的get方法从Buffer中读取数据。</li>
</ol>
<h2 id="flip方法">flip方法</h2>
<p>Buffer从写模式切换到读模式，将position值重置为0，limit的值设置为之前的position的值。</p>
<h2 id="selector检测多个nio-channel-读或写事件是否就绪">Selector，检测多个NIO channel， 读或写事件是否就绪。</h2>
<p>多个Channel以<strong>事件的方式</strong>可以注册到同一个Selector，从而达到用一个线程处理多个请求成为可能。</p>
<h2 id="代码演示">代码演示</h2>
<pre><code class="language-java"><div>    <span class="hljs-comment">//初始化buffer，基本类型除了boolean都有对应的buffer</span>
    IntBuffer intBuffer = IntBuffer.allocate(容量);
    <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; intBuffer.capacity(); i++){<span class="hljs-comment">// capacity得到容量大小</span>
        intBuffer.put(值);<span class="hljs-comment">//存入值</span>
    }
    <span class="hljs-comment">//读写切换</span>
    intBuffer.flip();

    <span class="hljs-keyword">while</span>(intBuffer.hasRemaining()){ <span class="hljs-comment">// 如果还有</span>
        System.out.println(intBuffer.get()); <span class="hljs-comment">//使用intBuffer.get()索引会移动</span>
    }
</div></code></pre>
<h2 id="buffer">Buffer</h2>
<ol>
<li>ByteBuffer</li>
<li>CharBuffer等</li>
</ol>
<h2 id="channel">Channel</h2>
<ol>
<li>FileChannel 文件</li>
<li>DatagramChanel UDP协议</li>
<li>SocketChanel TCP协议</li>
<li>ServerSocketChannel 用于TCP服务器端的监听和链接</li>
</ol>
<h2 id="channelbufferselector">Channel，Buffer，Selector</h2>
<ol>
<li>Selector对应一个线程</li>
<li>一个线程有多个Channel</li>
<li>channel注册到Selector中</li>
<li>Selector会根据不同的事件，在各个通道上切换</li>
<li>buffer是一个内存块，底层是一个数组</li>
<li>通过buffer读写数据，buffer是双向的，既可以读也可以写，需要通过flip方法切换。</li>
</ol>
<h2 id="切换channel的事件">切换Channel的事件</h2>
<h2 id="代码演示-1">代码演示</h2>
<pre><code class="language-java"><div><span class="hljs-comment">/*创建文件，向文件中写入数据*/</span>
<span class="hljs-keyword">try</span> {
    <span class="hljs-comment">/*如果文件不存在，创建该文件,文件后缀是不是文本文件不重要*/</span>
    File file = <span class="hljs-keyword">new</span> File(<span class="hljs-string">"E:/noi_utf8.data"</span>);
    <span class="hljs-keyword">if</span>(!file.exists()){
        file.createNewFile();
    }
    <span class="hljs-comment">/*根据文件输出流创建与这个文件相关的通道*/</span>
    FileOutputStream fos = <span class="hljs-keyword">new</span> FileOutputStream(file);
    FileChannel fc = fos.getChannel();
    <span class="hljs-comment">/*创建ByteBuffer对象， position = 0, limit = 64, capacity = 64*/</span>
    ByteBuffer bb = ByteBuffer.allocate(<span class="hljs-number">64</span>);
    <span class="hljs-comment">/*向ByteBuffer中放入字符串UTF-8的字节, position = 17, limit = 64*/</span>
    bb.put(<span class="hljs-string">"Hello,World 123 \n"</span>.getBytes(<span class="hljs-string">"UTF-8"</span>));
    <span class="hljs-comment">/*flip方法  position = 0, limit = 17*/</span>
    bb.flip();
    <span class="hljs-comment">/*write方法使得ByteBuffer的position到 limit中的元素写入通道中*/</span>
    fc.write(bb);
    <span class="hljs-comment">/*clear方法使得position = 0， limit = 64*/</span>
    bb.clear();
    <span class="hljs-comment">/*下面的代码同理*/</span>
    bb.put(<span class="hljs-string">"你好，世界 456"</span>.getBytes(<span class="hljs-string">"UTF-8"</span>));
    bb.flip();
    fc.write(bb);
    bb.clear();
    fos.close();
    fc.close();
} <span class="hljs-keyword">catch</span> (FileNotFoundException e) {} <span class="hljs-keyword">catch</span> (IOException e) {
    System.out.println(e);
}
<span class="hljs-comment">/*从刚才的文件中读取字符序列*/</span>
<span class="hljs-keyword">try</span> {
    <span class="hljs-comment">/*通过Path对象创建文件通道*/</span>
    Path path = Paths.get(<span class="hljs-string">"E:/noi_utf8.data"</span>);
    FileChannel fc = FileChannel.open(path);
    ByteBuffer bb = ByteBuffer.allocate((<span class="hljs-keyword">int</span>) fc.size()+<span class="hljs-number">1</span>);
    Charset utf8 = Charset.forName(<span class="hljs-string">"UTF-8"</span>);
    <span class="hljs-comment">/*阻塞模式，读取完成才能返回*/</span>
    fc.read(bb);
    bb.flip();
    CharBuffer cb = utf8.decode(bb);
    System.out.print(cb.toString());
    bb.clear();
    fc.close();
} <span class="hljs-keyword">catch</span> (IOException e) {
    e.printStackTrace();
}
</div></code></pre>
<h1 id="netty">Netty</h1>
<h2 id="简介">简介</h2>
<ol>
<li>由JBOSS提出，现在是Github上的独立项目。</li>
<li>一个<strong>异步的</strong>、基于<strong>事件驱动</strong>的<strong>网络应用框架</strong>，用以高速开发高性能、高可靠的网络IO程序。</li>
<li>针对TCP协议下，面向Clients端的高并发应用，或者Peer-to-Peer场景下的大量数据持续传输的应用。</li>
<li>一个NIO框架，适用于服务器通信相关的应用场景。</li>
</ol>
<blockquote>
<p>大数据领域经典的hadoop的高性能同行和序列化组件Avro的RPC框架默认采用Netty进行跨站点通信。
NettyService基于Netty框架二次封装实现。
spark使用netty作为底层</p>
</blockquote>
<h2 id="nettytcpipniojava之间的关系">Netty、TCP/IP、NIO、Java之间的关系</h2>
<div class="mxgraph" style="max-width:100%;border:1px solid transparent;" data-mxgraph="{&quot;highlight&quot;:&quot;#0000ff&quot;,&quot;nav&quot;:true,&quot;resize&quot;:true,&quot;toolbar&quot;:&quot;zoom layers lightbox&quot;,&quot;edit&quot;:&quot;_blank&quot;,&quot;xml&quot;:&quot;&lt;mxfile host=\&quot;b8a6fb74-a9a5-4499-b545-4e78fb96276e\&quot; modified=\&quot;2020-11-06T03:38:56.938Z\&quot; agent=\&quot;5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Code/1.49.3 Chrome/83.0.4103.122 Electron/9.2.1 Safari/537.36\&quot; etag=\&quot;gCbRxqsn9890zxkb99tO\&quot; version=\&quot;13.6.5\&quot;&gt;&lt;diagram id=\&quot;mCgDJnjrXh4s2DivoerU\&quot; name=\&quot;Page-1\&quot;&gt;&lt;mxGraphModel dx=\&quot;684\&quot; dy=\&quot;618\&quot; grid=\&quot;1\&quot; gridSize=\&quot;10\&quot; guides=\&quot;1\&quot; tooltips=\&quot;1\&quot; connect=\&quot;1\&quot; arrows=\&quot;1\&quot; fold=\&quot;1\&quot; page=\&quot;1\&quot; pageScale=\&quot;1\&quot; pageWidth=\&quot;827\&quot; pageHeight=\&quot;1169\&quot; math=\&quot;0\&quot; shadow=\&quot;0\&quot;&gt;&lt;root&gt;&lt;mxCell id=\&quot;0\&quot;/&gt;&lt;mxCell id=\&quot;1\&quot; parent=\&quot;0\&quot;/&gt;&lt;mxCell id=\&quot;5\&quot; value=\&quot;&amp;lt;font color=&amp;quot;#474747&amp;quot;&amp;gt;原生Java&amp;lt;/font&amp;gt;\&quot; style=\&quot;rounded=0;whiteSpace=wrap;html=1;strokeWidth=1;fillColor=#FFFFFF;strokeColor=#2A2A2A;\&quot; vertex=\&quot;1\&quot; parent=\&quot;1\&quot;&gt;&lt;mxGeometry x=\&quot;354\&quot; y=\&quot;230\&quot; width=\&quot;120\&quot; height=\&quot;60\&quot; as=\&quot;geometry\&quot;/&gt;&lt;/mxCell&gt;&lt;mxCell id=\&quot;6\&quot; value=\&quot;&amp;lt;font color=&amp;quot;#2a2a2a&amp;quot;&amp;gt;TCP/IP协议&amp;lt;/font&amp;gt;\&quot; style=\&quot;rounded=0;whiteSpace=wrap;html=1;strokeWidth=1;fillColor=#FFFFFF;strokeColor=#2A2A2A;\&quot; vertex=\&quot;1\&quot; parent=\&quot;1\&quot;&gt;&lt;mxGeometry x=\&quot;354\&quot; y=\&quot;290\&quot; width=\&quot;120\&quot; height=\&quot;60\&quot; as=\&quot;geometry\&quot;/&gt;&lt;/mxCell&gt;&lt;mxCell id=\&quot;9\&quot; value=\&quot;&amp;lt;font color=&amp;quot;#474747&amp;quot;&amp;gt;Not Only I/O&amp;lt;/font&amp;gt;\&quot; style=\&quot;rounded=0;whiteSpace=wrap;html=1;strokeWidth=1;fillColor=#FFFFFF;strokeColor=#2A2A2A;\&quot; vertex=\&quot;1\&quot; parent=\&quot;1\&quot;&gt;&lt;mxGeometry x=\&quot;354\&quot; y=\&quot;170\&quot; width=\&quot;120\&quot; height=\&quot;60\&quot; as=\&quot;geometry\&quot;/&gt;&lt;/mxCell&gt;&lt;mxCell id=\&quot;10\&quot; value=\&quot;&amp;lt;font color=&amp;quot;#474747&amp;quot;&amp;gt;Netty&amp;lt;/font&amp;gt;\&quot; style=\&quot;rounded=0;whiteSpace=wrap;html=1;strokeWidth=1;fillColor=#FFFFFF;strokeColor=#2A2A2A;\&quot; vertex=\&quot;1\&quot; parent=\&quot;1\&quot;&gt;&lt;mxGeometry x=\&quot;354\&quot; y=\&quot;110\&quot; width=\&quot;120\&quot; height=\&quot;60\&quot; as=\&quot;geometry\&quot;/&gt;&lt;/mxCell&gt;&lt;/root&gt;&lt;/mxGraphModel&gt;&lt;/diagram&gt;&lt;/mxfile&gt;&quot;}"></div>
<h2 id="三种io模型">三种IO模型</h2>
<h3 id="传统bio">传统BIO</h3>
<p>同步阻塞</p>
<h3 id="nio-1">NIO</h3>
<p>同步非阻塞</p>
<h3 id="aio">AIO</h3>
<p>异步非阻塞</p>
<h2 id="使用telnet连接服务器">使用telnet连接服务器</h2>
<ol>
<li>telnet ip</li>
<li>发送消息 ctrl + ]</li>
</ol>
<h2 id="netty和tomcat有什么区别">Netty和Tomcat有什么区别？</h2>
<p>Netty和Tomcat最大的区别就在于通信协议，Tomcat是基于Http协议的，他的实质是一个基于http协议的web容器，但是Netty不一样，他能通过编程自定义各种协议，因为netty能够通过codec自己来编码/解码字节流，完成类似redis访问的功能，这就是netty和tomcat最大的不同。</p>
<h2 id="tomcat从6x开始就支持了nio模式后续推出apr模式">tomcat从6.x开始就支持了nio模式，后续推出APR模式</h2>
<p>APR模式，一种通过jni调用apache网络库的模式，相比于旧的bio模式，并发性能得到了很大提高，特别是APR模式，而netty是否比tomcat性能更高，则要取决于netty程序作者的技术实力了。</p>
<h2 id="netty的优点">Netty的优点</h2>
<ol>
<li>并发高</li>
<li>传输快</li>
<li>封装好</li>
</ol>
<h2 id="netty使用">Netty使用</h2>
<ol>
<li>搭建netty服务器，</li>
<li>编写启动类，负责启动BootStrap；编写ChannelHandler负责业务逻辑。</li>
</ol>
<pre><code class="language-java"><div>
<span class="hljs-keyword">import</span> io.netty.bootstrap.ServerBootstrap;
<span class="hljs-keyword">import</span> io.netty.channel.ChannelInitializer;
<span class="hljs-keyword">import</span> io.netty.channel.ChannelOption;
<span class="hljs-keyword">import</span> io.netty.channel.nio.NioEventLoopGroup;
<span class="hljs-keyword">import</span> io.netty.channel.socket.SocketChannel;
<span class="hljs-keyword">import</span> io.netty.channel.socket.nio.NioServerSocketChannel;
<span class="hljs-keyword">import</span> io.netty.handler.codec.http.HttpObjectAggregator;
<span class="hljs-keyword">import</span> io.netty.handler.codec.http.HttpRequestDecoder;
<span class="hljs-keyword">import</span> io.netty.handler.codec.http.HttpResponseEncoder;

<span class="hljs-comment">/**
 * Created by RoyDeng on 17/7/20.
 */</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HttpServer</span> </span>{

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> port;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">HttpServer</span><span class="hljs-params">(<span class="hljs-keyword">int</span> port)</span> </span>{
        <span class="hljs-keyword">this</span>.port = port;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> Exception </span>{
        <span class="hljs-keyword">if</span> (args.length != <span class="hljs-number">1</span>) {
            System.err.println(
                    <span class="hljs-string">"Usage: "</span> + HttpServer.class.getSimpleName() +
                            <span class="hljs-string">" &lt;port&gt;"</span>);
            <span class="hljs-keyword">return</span>;
        }
        <span class="hljs-keyword">int</span> port = Integer.parseInt(args[<span class="hljs-number">0</span>]);
        <span class="hljs-keyword">new</span> HttpServer(port).start();
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">start</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> Exception </span>{
        ServerBootstrap b = <span class="hljs-keyword">new</span> ServerBootstrap();
        NioEventLoopGroup group = <span class="hljs-keyword">new</span> NioEventLoopGroup();
        b.group(group)
                .channel(NioServerSocketChannel.class)
                .childHandler(<span class="hljs-keyword">new</span> ChannelInitializer&lt;SocketChannel&gt;() {
                    <span class="hljs-meta">@Override</span>
                    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">initChannel</span><span class="hljs-params">(SocketChannel ch)</span>
                            <span class="hljs-keyword">throws</span> Exception </span>{
                        System.out.println(<span class="hljs-string">"initChannel ch:"</span> + ch);
                        ch.pipeline()
                                .addLast(<span class="hljs-string">"decoder"</span>, <span class="hljs-keyword">new</span> HttpRequestDecoder())   <span class="hljs-comment">// 1</span>
                                .addLast(<span class="hljs-string">"encoder"</span>, <span class="hljs-keyword">new</span> HttpResponseEncoder())  <span class="hljs-comment">// 2</span>
                                .addLast(<span class="hljs-string">"aggregator"</span>, <span class="hljs-keyword">new</span> HttpObjectAggregator(<span class="hljs-number">512</span> * <span class="hljs-number">1024</span>))    <span class="hljs-comment">// 3 添加aggregator后才能时使用，fullhttpRequest和FullHttpRequest，不添加http请求会被多个Chanel处理，对于业务处理不方便。</span>
                                .addLast(<span class="hljs-string">"handler"</span>, <span class="hljs-keyword">new</span> HttpHandler());   <span class="hljs-comment">// 4 添加处理接口。</span>
                    }
                })
                .option(ChannelOption.SO_BACKLOG, <span class="hljs-number">128</span>) <span class="hljs-comment">// determining the number of connections queued</span>
                .childOption(ChannelOption.SO_KEEPALIVE, Boolean.TRUE);

        b.bind(port).sync();
    }
}
</div></code></pre>
<h1 id="websocket">WebSocket</h1>
<ol>
<li>HTML提出的一种新协议，采用全双工（同时双向）。</li>
<li>解决通信效率低。</li>
<li>长链接</li>
<li>spring weebsocket 坐标</li>
<li>socketjs</li>
<li>协议：ws://</li>
</ol>
<h2 id="入门-基于spring的简单使用">入门， 基于Spring的简单使用</h2>
<h3 id="首先在pom文件引入spring-boot-starter-websocket等依赖">首先在POM文件引入spring-boot-starter-websocket等依赖。</h3>
<h3 id="后台使用步骤">后台使用步骤</h3>
<p>使用步骤：创建WebSocket服务端。
核心思路：</p>
<p>① 通过注解@ServerEndpoint来声明实例化WebSocket服务端。
② 通过注解@OnOpen、@OnMessage、@OnClose、@OnError 来声明回调函数。
事件类型	WebSocket服务端注解	事件描述
open	@OnOpen	当打开连接后触发
message	@OnMessage	当接收客户端信息时触发
error	@OnError	当通信异常时触发
close	@OnClose	当连接关闭时触发</p>
<pre><code class="language-java"><div><span class="hljs-comment">// spring容器需要创建bean</span>
<span class="hljs-meta">@Configuration</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">WebSocketConfig</span> </span>{
    <span class="hljs-meta">@Bean</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> ServerEndpointExporter <span class="hljs-title">serverEndpointExporter</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> ServerEndpointExporter();
    }
}

<span class="hljs-comment">// tomcat 7后能直接使用</span>
<span class="hljs-meta">@Component</span>
<span class="hljs-meta">@ServerEndpoint</span>(<span class="hljs-string">"/chat"</span>)<span class="hljs-comment">//标记此类为服务端</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">WebSocketChatServer</span> </span>{
    <span class="hljs-comment">/**
     * 全部在线会话  PS: 基于场景考虑 这里使用线程安全的Map存储会话对象。
     */</span>
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> Map&lt;String, Session&gt; onlineSessions = <span class="hljs-keyword">new</span> ConcurrentHashMap&lt;&gt;();
    <span class="hljs-comment">/**
     * 当客户端打开连接：1.添加会话对象 2.更新在线人数
     */</span>
    <span class="hljs-meta">@OnOpen</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onOpen</span><span class="hljs-params">(Session session)</span> </span>{
        onlineSessions.put(session.getId(), session);
        sendMessageToAll(xxxx);
    }
    <span class="hljs-comment">/**
     * 当客户端发送消息：1.获取它的用户名和消息 2.发送消息给所有人
     * &lt;p&gt;
     * PS: 这里约定传递的消息为JSON字符串 方便传递更多参数！
     */</span>
    <span class="hljs-meta">@OnMessage</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onMessage</span><span class="hljs-params">(Session session, String jsonStr)</span> </span>{
        Message message = JSON.parseObject(jsonStr, Message.class);
        sendMessageToAll(xxxx);
    }
    <span class="hljs-comment">/**
     * 当关闭连接：1.移除会话对象 2.更新在线人数
     */</span>
    <span class="hljs-meta">@OnClose</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onClose</span><span class="hljs-params">(Session session)</span> </span>{
        onlineSessions.remove(session.getId());
        sendMessageToAll(xxxx);
    }
    <span class="hljs-comment">/**
     * 当通信发生异常：打印错误日志
     */</span>
    <span class="hljs-meta">@OnError</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onError</span><span class="hljs-params">(Session session, Throwable error)</span> </span>{
        error.printStackTrace();
    }
    <span class="hljs-comment">/**
     * 公共方法：发送信息给所有人
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">sendMessageToAll</span><span class="hljs-params">(String msg)</span> </span>{
        <span class="hljs-keyword">try</span> {
            session.getBasicRemote().sendText(msg);
        } <span class="hljs-keyword">catch</span> (IOException e) {
            e.printStackTrace();
        }
    }
} 
</div></code></pre>
<h3 id="前台使用步骤">前台使用步骤</h3>
<p>使用步骤：1、获取WebSocket客户端对象。</p>
<ul>
<li>WebSocket客户端 PS：URL开头表示WebSocket协议 中间是域名端口 结尾是服务端映射地址</li>
<li>var url = &quot;ws://&quot;+document.location.host+&quot;${base}/websocket/test&quot;; 提示用法
例如： var webSocket = new WebSocket(url);务</li>
</ul>
<p>使用步骤：2、获取WebSocket回调函数。
例如：webSocket.onmessage = function (event) {console.log('WebSocket收到消息：' + event.data);
事件类型	WebSocket回调函数	事件描述
open	webSocket.onopen	当打开连接后触发
message	webSocket.onmessage	当客户端接收服端数据时触发
error	webSocket.onerror	当通信异常时触发
close	webSocket.onclose	当连接关闭时触发
使用步骤：3、发送消息给服务端
例如：webSokcet.send(jsonStr) 结合实际场景 本案例采用JSON字符串进行消息通信。</p>
<h1 id="jdbc访问数据库">JDBC访问数据库</h1>
<h2 id="什么是数据库索引">什么是数据库索引</h2>
<p>根据数据库的功能，可以在数据库设计器中创建索引：<strong>唯一索引、主键索引和聚集索引</strong>。</p>
<p><strong>唯一索引</strong>：表中的任意两行的索引值都不相等</p>
<p><strong>主键索引和唯一索引的区别：</strong></p>
<ol>
<li>主键一定会创建一个唯一索引，但是有唯一索引的列不一定是主键；</li>
<li>主键不允许为空值，唯一索引列允许空值；</li>
<li>一个表只能有一个主键，但是可以有多个唯一索引；</li>
<li>主键可以被其他表引用为外键，唯一索引列不可以；</li>
<li>主键是一种约束，而唯一索引是一种索引，是表的冗余数据结构，两者有本质的差别</li>
</ol>
<p><strong>聚集索引</strong>指示表中数据行按索引键的排序次序存储，聚集索引对查找行很有效。只有当表包含聚集索引时，表内的数据行才按索引列的值在磁盘上进行物理上排序和存储。<strong>每一个表只能有一个聚集索引</strong>，因为数据行本身只能按一个顺序存储。</p>
<h2 id="什么是jdbc">什么是JDBC</h2>
<p>Java DataBase Connectivity, JDBC 用于在Java程序中实现数据库操作，他提供执行sql语句、访问数据库的各种方法，并为各种不同的数据库提供统一的操作接口，java.sql包中包含了JDBC操作数据库的所有类。</p>
<h2 id="jdbc访问数据库步骤">JDBC访问数据库步骤</h2>
<ol>
<li>加载JDBC驱动器。将对应的jar包放入classpath目录中</li>
<li>加载JDBC驱动，并将其注册到DriverManager中。一般使用Class.forName(String driverName)</li>
<li>建立数据库连接，DriverManager.getConnection(url, username, passwd)</li>
<li>建立Statement对象或者PreparedStatement对象。</li>
<li>执行sql语句</li>
<li>访问结果集ResultSet对象。</li>
<li>关闭Result、Statement、PrepareStatement、Connection对象，释放掉所占用的资源。</li>
</ol>
<h2 id="为什么关闭resultstatementpreparestatementconnection对象">为什么关闭Result、Statement、PrepareStatement、Connection对象？</h2>
<details>
<summary>答案</summary>
<p>防止内存泄漏。释放资源，未完！</p>
</details>
<h2 id="jdbc处理事务采用什么方法">JDBC处理事务采用什么方法</h2>
<ol>
<li>一般来说事务操作是自动提交。所以要关闭事务自动提交--setAutoCommit(false)</li>
<li>使用commit()，rollback()方法, 注意异常</li>
</ol>
<h2 id="jdbc有哪些事务隔离级别">JDBC有哪些事务隔离级别？</h2>
<blockquote>
<p>为了解决“多个线程请求相同数据”相关的问题，事物间通常会用锁相互隔离开来。JDBC支持不同类型的事务，由Connection对象指派或确定。</p>
</blockquote>
<h2 id="jdbc指定事务级别">JDBC指定事务级别</h2>
<p>通过Connection对象的setTrasactionLevel()方法来设置隔离级别，通过getTransactionIsolation()来确定当前事务的级别。</p>
<h3 id="jdbc-定义了5种事务级别未完成">JDBC 定义了5种事务级别（未完成）</h3>
<ol>
<li>TRANSACTION_NONE JDB. 不支持事务</li>
<li>TRANSACTION_READ_UNCOMMITTED. 未提交读。</li>
<li>TRANSACTION_READ_COMMITTED.已提交读。</li>
<li>TRANSACTION_REPEATABLE_READ. 可重复读。</li>
<li>TRANSACTION_SERIALIZABLE. 可序列化。</li>
</ol>
<h2 id="classforname">Class.forName</h2>
<ol>
<li>一种创建对象的方式---类加载机制</li>
<li>把类加载到JVM中，返回一个带有给定字符串名的类或接口相关的Class对象，并且JVM会加载这个类，同时JVM会执行该类的静态代码块。Class对象使用newInstance()创建对象。</li>
<li>使用类加载机制创建对象能<strong>提高软件的可扩展性</strong>，简单的例子：命令台交互对应的类名，让程序完成不同的业务。</li>
</ol>
<h2 id="jdbc中的classforname驱动">JDBC中的Class.forName(驱动)</h2>
<pre><code class="language-java"><div>    <span class="hljs-comment">//JDBC中含有下面静态代码块, 将对应的驱动注册到DriverManager中，所以后面使用DriverManager得到Connection</span>
    java.sql.DriverManager.rigisterDriver(<span class="hljs-keyword">new</span> Driver());
</div></code></pre>
<h2 id="statementpreparedstatement和callablestatement">Statement、PreparedStatement和CallableStatement</h2>
<h3 id="它们的作用">它们的作用</h3>
<ol>
<li>Statement执行不带参数的sql语句。</li>
<li>PreparedStatement表示预编译的sql语句。占位符是?</li>
<li>CallableStatement提供了调用数据库中存储过程的接口。</li>
</ol>
<h3 id="statement与preparedstatement相比preparedstatement的优点">Statement与PreparedStatement相比PreparedStatement的优点</h3>
<ol>
<li>效率高，PreparedStatement执行sql语句时，命令会被数据库进行编译和解析，并放到缓存区。只编译解析一次，可以重复使用，提高系统性能。</li>
<li>代码可读性和可维护性更好。 Statement变量需要拼接。PreparedStatement只需要占位符。</li>
<li>安全性更好，preparedStatement能预防SQL注入。</li>
</ol>
<h3 id="callablestatement">CallableStatement</h3>
<blockquote>
<p>CallableStatement对象为所有的RDBMS（Relational Database Management System， 关系型数据库）提供一种标准形式调用存储过程的方法。</p>
</blockquote>
<ol>
<li>由prepareCall()创建</li>
<li>继承了PreparedStatement中用于数据入参数的方法</li>
<li>增加了调用数据库中的存储过程和函数以及设置输出类型的功能。</li>
</ol>
<h2 id="getstring和getobject的区别">getString()和getObject()的区别</h2>
<ol>
<li>getString()、getInt()、getDate()等方法<strong>适用于查询量小的情况</strong>，这些方法一次性的把数据放到内存，通过调用Result的next()和getString()等方法获取数据。数据量大了，会抛出OracleException（以Oracle为例）。</li>
<li>getObject()不会一次读到内存中，每次直接从数据库中获取数据，<strong>不会因为数据量大而出错</strong>。</li>
</ol>
<h2 id="使用jdbc需要注意哪些问题">使用JDBC需要注意哪些问题？</h2>
<ol>
<li>正常使用连接数据库（Connection）的资源。可以利用连接池，不必释放，因为打开过程也是耗费资源。</li>
<li>最好在执行了executeXXX，不需要ResultSet后立马关闭Statment，每次执行conn.createStatement()或conn.prepareStatement()相当于打开一个cursor（游标）</li>
</ol>
<h2 id="什么是jdo">什么是JDO？</h2>
<ol>
<li>Java Data Object， Java数据对象，用于存取某种数据仓库中的对象的标准化API，他能使开发人员间接的访问数据库。</li>
<li>它是JDBC的补充，存储数据不需要额外的代码。它使得应用可移植性更强。</li>
</ol>
<h2 id="jdbc与hibernate有什么区别">JDBC与Hibernate有什么区别？</h2>
<ol>
<li>Hibernate是JDBC的封装,将连接参数写到xml文件中，对数据库的访问还是通过jdbc完成</li>
<li>Hibernate是持久层的框架，他将表的信息映射到xml，再将xml映射到持久化类中。这样可以使用Hibernate独特的插叙语句--（Hibernate Query Language，HQL）。Hibernate的查询语句返回List&lt;Object[.]&gt;类。</li>
<li>Hibernate具有访问层（Data Access Object， DAO），因此hibernate具有很好的维护性和扩展性。</li>
</ol>
<h2 id="了解jdbc元数据数据库框架基础">了解JDBC元数据(数据库框架基础)</h2>
<h1 id="jsp和servlet">JSP和Servlet</h1>
<h2 id="http中get和post方法有什么区别">HTTP中GET和POST方法有什么区别</h2>
<ol>
<li>http的请求方法有很多种，get是最简单的一种请求方法，get方法主要用于获取服务器资源信息（也可以上传数据）。最好不要用来修改服务器资源；post除了能够从服务器端获取资源，同时还可以向服务器长传资源。</li>
<li>采用get方法向服务器上传数据时，一般将数据添加到url，url长度存在限制（1024byte左右），post请求是将数据放在请求体上。</li>
<li>采用get方法上传数据，存在安全隐患，数据会明文显示到url上，post相对安全。</li>
</ol>
<h2 id="什么是servlet">什么是Servlet</h2>
<h2 id="jsp有哪些优点">JSP有哪些优点</h2>
<h2 id="jsp和servlet的异同">JSP和Servlet的异同</h2>
<h2 id="forward转发和redirect重定向有什么区别">forward（转发）和redirect（重定向）有什么区别</h2>
<h2 id="jsp的内置对象有哪些">jsp的内置对象有哪些</h2>
<h2 id="request对象有哪些方法">request对象有哪些方法</h2>
<h2 id="jsp有哪些动作">jsp有哪些动作</h2>
<h2 id="jsp中include指令和include动作有什么区别">jsp中include指令和include动作有什么区别</h2>
<h2 id="会话跟踪技术有哪些">会话跟踪技术有哪些</h2>
<h2 id="web中如何指定字符串的编码">web中如何指定字符串的编码</h2>
<h2 id="什么是ajax">什么是ajax</h2>
<h2 id="cookie和session有什么区别">cookie和session有什么区别</h2>
<h2 id="过滤器和拦截器">过滤器和拦截器</h2>
<blockquote>
<p>拦截器基于java的反射机制, 不依赖于servlet容器.Spring MVC的拦截器, 实现HandlerInterceptor或者继承HandlerInterceptor接口的实现类.实现WebRequestInterceptor或继承WebRequestInterceptor接口的实现类来定义.在spring mvc配置文件种配置拦截器 <code>&lt;mvc:interceptors&gt;</code>.Springboot中通过实现WebMvcConfigurer配合@Configuration来配置.</p>
<p>过滤器基于方法的回调,依赖于servlet容器,对所有请求起作用.启动时间先于servlet.过滤器实现javax.servlet.Filter接口.注解优先启动.监听器优先于过滤器启动</p>
</blockquote>
<pre><code class="language-xml"><div><span class="hljs-tag">&lt;<span class="hljs-name">filter</span>&gt;</span>
	<span class="hljs-tag">&lt;<span class="hljs-name">filter-name</span>&gt;</span>springSecurityFilterChain<span class="hljs-tag">&lt;/<span class="hljs-name">filter-name</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">filter-class</span>&gt;</span>org.springframework.web.filter.DelegationgFilterProxy<span class="hljs-tag">&lt;/<span class="hljs-name">filter-class</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">filter</span>&gt;</span>
<span class="hljs-comment">&lt;!--配置过滤器--&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">filter-mapping</span>&gt;</span>
	<span class="hljs-tag">&lt;<span class="hljs-name">filter-name</span>&gt;</span>springSecurityFilterChain<span class="hljs-tag">&lt;/<span class="hljs-name">filter-name</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">url-pattern</span>&gt;</span>/*<span class="hljs-tag">&lt;/<span class="hljs-name">url-pattern</span>&gt;</span> <span class="hljs-comment">&lt;!-- 过滤全部 --&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">filter-mapping</span>&gt;</span>
</div></code></pre>
<h2 id="监听器listener">监听器Listener</h2>
<p>分为三类8种(监听三个域对象):</p>
<p>监听三个域对象的创建和销毁: ServletContextListener, HttpSessionListener, ServletRequestListener</p>
<p>监听三个域对象属性变更(属性的添加,移除,替换):ServletContextAttributeListener, HttpSessionAtributeListener, ServletRequestAttributeListerner</p>
<p>监听HttpSession种的JavaBean的状态改变(绑定,解除绑定,钝化,活化): HttpSessionBindingListener, HttpSessionActivationListene</p>
<p>事件源: Servlet种的三个域对象.ServletContext,HttpSession,ServletRequest.</p>
<p>监听器: 自定义类实现8个接口</p>
<p>事件源和监听器绑定: 配置.</p>
<p>以ServletContextListener为例:实现ServletContextListener,contextDestroyed方法和contextInitialized方法分别代表应用销毁,创建属于该Web项目的ServletContext对象时</p>
<pre><code class="language-xml"><div><span class="hljs-comment">&lt;!--web.xml--&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">listener</span>&gt;</span>
	<span class="hljs-tag">&lt;<span class="hljs-name">listener-class</span>&gt;</span>接口的实现<span class="hljs-tag">&lt;/<span class="hljs-name">listener-class</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">listener</span>&gt;</span>
</div></code></pre>
<h1 id="j2ee与ejb">J2EE与EJB</h1>
<h1 id="项目升级">项目升级</h1>
<ol>
<li>单机模式：用户访问服务器（服务器软件， 数据库放一起）</li>
<li>服务器和数据库分离</li>
<li>引入本地缓存和分布式缓存</li>
<li>引入反向代理（软件：Nginx、HAProxy，两者都是网络第七层的反向代理软件，主要支持http协议，涉及session共享、文件上传下载）实现负载均衡</li>
<li>数据库读写分离（使用数据库的中间件Mycat）</li>
<li>数据库按业务分离</li>
<li>使用LVS或F5使用多个Nginx负载均衡</li>
</ol>
<h1 id="window端口占用">window端口占用</h1>
<h2 id="查询端口-netstat--anofindstr-端口号">查询端口： netstat -ano|findstr 端口号</h2>
<h2 id="任务结束-taskkill-pid-进程号-f">任务结束： taskkill /pid 进程号 /f</h2>
<h1 id="关于idea的使用">关于IDEA的使用</h1>
<h2 id="全局设置中配置mavengit等">全局设置中配置maven，git等</h2>
<h2 id="springboot的热部署">SpringBoot的热部署</h2>
<ol>
<li>在全局配置文件中配置setting&gt;build&gt;compiler 勾选build project automatically</li>
<li>ctrl + alt + shift + / 找到compiler.automake.allow.when.app.running并勾选</li>
</ol>
<h2 id="社区版本整合spring-boot">社区版本整合Spring Boot</h2>
<ol>
<li>setting&gt;plugins&gt;marketplace</li>
<li>搜索spring assistant</li>
<li>安装stater editor</li>
</ol>
<h2 id="常用快捷键及技巧">常用快捷键及技巧</h2>
<ol>
<li>提示： alt + enter</li>
<li>查找类： ctrl + n, ctrl + h 查看类的继承关系</li>
<li>点击旁边的I下划线可以看见实现，</li>
<li>xxx.for遍历,xxx.var 生成引用</li>
<li>***Ctrl+D***复制行、***Ctrl+&lt;/&gt;***折叠代码</li>
<li>shift + f6 更改文件名</li>
</ol>
<script type="text/javascript" src="https://app.diagrams.net/js/viewer-static.min.js"></script>
    </body>
    </html>